/*******************************************************************************
 * Package: com.song.boot.springstudy.netty.simple.handler
 * Type:    NettyServerHandler
 * Date:    2023-06-04 17:48
 *
 * Copyright (c) 2023 HUANENG GUICHENG TRUST CORP.,LTD All Rights Reserved.
 *
 * You may not use this file except in compliance with the License.
 *******************************************************************************/
package com.song.boot.springstudy.netty.chat.selfish;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;

/**
 * 需求：私聊系统设计思路
 *      服务端：
 *      无需群聊系统中的channelGroup   当前代码含有  懒得剔除 （主要实现为私聊系统channelMap）
 *      channelMap:key：当前登录用户的唯一id ：port   value：Channel (id为客户端端口）注意敲定唯一
 *      客户端加入服务器时调用的方法-即加入
 *          handlerAdded->channelMap.put(socketAddress.getPort(), channel); 存入对应channel
 *      发送消息时：去选择
 *          channelRead0->channelMap.get(Integer.valueOf(selectUserId));获取对应channel
 *
 *      客户端：
 *      发送过来的消息模型为：
 *          例如：61311&你好瑶瑶 （61311为对方的私聊端口）
 *      InetSocketAddress socketAddress = (InetSocketAddress)channel.localAddress();重要
 *      也可以自己给自己聊
 *
 * @author Songxianyang
 * @date 2023-06-04 17:48
 * 自定义一个处理器，需要继承netty规定好的某个HandlerAdapter
 */
@Slf4j
public class ChartNettyServerHandler extends SimpleChannelInboundHandler<String> {
    /**
     * key：当前登录用户的唯一id ：port   value：Channel
     */
    private static Map<Integer, Channel> channelMap = new HashMap<>();

    //定义一个channle 组，管理所有的channel
    //GlobalEventExecutor.INSTANCE) 是全局的事件执行器，是一个单例
    private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
        // 当前 客户端 channel
        Channel channel1 = channelHandlerContext.channel();
        System.out.println("获取当前客户端消息为："+s);
        // 选择的用户  进行私聊开始
        String[] split = s.split("&");
        String selectUserId = split[0];
        String msg = split[1];
        Channel channel = channelMap.get(Integer.valueOf(selectUserId));
        System.out.println("消息已推送给私聊用户为："+">>>>>>"+channel.remoteAddress());
        System.out.println("对方用户id为："+">>>>>>"+channel.hashCode());
        channel.writeAndFlush(">>>>>"+channel1.remoteAddress()+"发送过来的消息为：：：："+msg);

    }
    //表示channel 处于活动状态, 提示 上线
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("---------------"+ctx.channel().remoteAddress()+"--------------------"+"上线！开始聊天吧！");
    }
    //表示channel 处于不活动状态, 提示 xx离线了
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("---------------"+ctx.channel().remoteAddress()+"--------------------"+"离线！");

    }

    /**
     * C、S端一单建立Channel连接，就会触发该方法
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        // 给其他客户端发送某某加入群聊
        Channel channel = ctx.channel();
        InetSocketAddress socketAddress = (InetSocketAddress)channel.remoteAddress();
        // 获取客户端发channel。hashcode
        System.out.println("客户端channel.id=="+socketAddress.getPort());
        channelGroup.writeAndFlush("客户端：》》》》" + socketAddress + "已加入群聊系统，注意隐士安全！可以发起私聊欧！");
        channelGroup.add(channel);
        // 放入私聊channel
        log.info("channel.remoteAddress()----》{}",channel.remoteAddress());
        log.info("handlerAdded: 获取唯一标识绑定channel----》{}",socketAddress.getPort());
        channelMap.put(socketAddress.getPort(), channel);
    }

    /**
     * Channel 下线，通知其他 客户端
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        channelGroup.writeAndFlush("客户端：》》》》" + channel.remoteAddress() + "退出群聊系统");
        System.out.println("在线用户为="+channelGroup.size());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
    }
}
